﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using MvvmCodeReduction.Helpers;
using MvvmCodeReduction.Model;

namespace MvvmCodeReduction.View.MVP
{
    public partial class CustomersMVP : Window, ICustomersViewMVP
    {
        public CustomersMVP()
        {
            InitializeComponent();
        }

        #region ICustomersViewMVP

        public string CancelText { get; set; }

        private IEnumerable<Model.Customer> _customers;
        public IEnumerable<Customer> Customers
        {
            get { return _customers; }
            set
            {
                _customers = value;
                DataContext = _customers;
            }
        }

        public event EventHandler<CustomerEventArgs> OnEdit = delegate { };
        public event EventHandler<CustomerEventArgs> OnCancel = delegate { };
        public event EventHandler<CustomerEventArgs> OnSave = delegate { };

        public bool ShowControl(string controlName, int customerID)
        {
            return SetVisibility(controlName, customerID, Visibility.Visible);
        }

        public bool HideControl(string controlName, int customerID)
        {
            return SetVisibility(controlName, customerID, Visibility.Collapsed);
        }

        public bool EnableControl(string controlName, int customerID)
        {
            return SetEnabled(controlName, customerID, true);
        }

        public bool DisableControl(string controlName, int customerID)
        {
            return SetEnabled(controlName, customerID, false);
        }

        public bool SetControlContent(string controlName, int customerID,
            object content)
        {
            ContentControl control =
                GetElement<ContentControl>(controlName, customerID);
            if (control == null) return false;
            control.Content = content;
            return true;
        }

        public bool GetTextBoxText(string controlName, int customerID, out string text)
        {
            text = null;
            TextBox textBox =
                GetElement<TextBox>(controlName, customerID);
            if (textBox == null) return false;
            text = textBox.Text;
            return true;
        }

        public bool SetTextBoxText(string controlName, int customerID, string text)
        {
            TextBox textBox =
                GetElement<TextBox>(controlName, customerID);
            if (textBox == null) return false;
            textBox.Text = text;
            return true;
        }

        public bool SetTextBlockText(string controlName, int customerID, string text)
        {
            TextBlock textBlock =
                GetElement<TextBlock>(controlName, customerID);
            if (textBlock == null) return false;
            textBlock.Text = text;
            return false;
        }

        #endregion ICustomersViewMVP

        #region Event Handlers

        private void EditButton_Click(object sender,
                                      RoutedEventArgs e)
        {
            Button button = sender as Button;
            if (button == null)
            {
                Alert("Unable to get button from sender.");
                return;
            }
            Customer customer = GetCurrentCustomer(sender);
            if (customer == null) return;


            if (button.Content.ToString() == CancelText)
            {
                OnCancel(this, new CustomerEventArgs {Customer = customer});
            }
            else
            {
                OnEdit(sender, new CustomerEventArgs { Customer = customer });                
            }
        }

        private void SaveButton_Click(object sender,
                                      RoutedEventArgs e)
        {
            Customer customer = GetCurrentCustomer(sender);
            if (customer == null) return;
            OnSave(sender, new CustomerEventArgs { Customer = customer });
        }

        #endregion Event Handlers

        #region Helpers

        private Model.Customer GetCurrentCustomer(object sender)
        {
            // Get controls
            var frameworkElement = sender as FrameworkElement;
            if (frameworkElement == null)
            {
                Alert(
                    "Unable to cast sender to FrameworkElement.");
                return null;
            }
            Model.Customer customer = frameworkElement.DataContext as Customer;
            if (customer == null)
            {
                Alert(
                    "Unable to retrieve customer from DataContext.");
            }
            return customer;
        }

        private bool SetVisibility(string controlName, int customerID,
            Visibility visibility)
        {
            FrameworkElement frameworkElement
                = GetElement<FrameworkElement>(controlName, customerID);

            if (frameworkElement == null) return false;

            frameworkElement.Visibility = visibility;
            return true;
        }

        private bool SetEnabled(string controlName, int customerID,
            bool enabled)
        {
            FrameworkElement frameworkElement
                = GetElement<FrameworkElement>(controlName, customerID);

            if (frameworkElement == null) return false;

            frameworkElement.IsEnabled = enabled;
            return true;
        }

        private T GetElement<T>(string controlName, int customerID)
            where T : FrameworkElement
        {
            Model.Customer customer = GetCustomer(customerID);
            T element
                = GetItemChildByCustomer<T>(
                    customer, controlName);
            return element;
        }

        private Customer GetCustomer(int customerID)
        {
            Customer customer =
                _customers.FirstOrDefault(c => c.ID == customerID);
            if (customer == null)
            {
                Alert("Unable to get customer with ID: " + customerID);
            }
            return customer;
        }

        private T GetItemChildByCustomer<T>(Customer customer,
                                            string controlName)
            where T : FrameworkElement
        {
            ContentPresenter contentPresenter =
                CustomersItemsControl.ItemContainerGenerator.
                    ContainerFromItem(customer)
                as ContentPresenter;
            if (contentPresenter == null)
            {
                Alert("Unable to get ContentPresenter for Customer : "
                    + customer.ID);
                return default(T);
            }
            IEnumerable<T> controls = UIHelpers.FindVisualChildren<T>(contentPresenter);
            if (controls == null)
            {
                Alert(
                    "Unable to retrieve " + typeof(T)
                    + " from DataContext.");
                return default(T);
            }
            return
                controls.FirstOrDefault(b => b.Name == controlName);
        }

        public void Alert(string message)
        {
            MessageBox.Show(message);
        }

        #endregion Helpers
    }
}
